import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';

import '../../dao/ImCollectDao.dart';
import '../../dao/ImMessageDao.dart';
import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import '../../service/ImMessageSendService.dart';
import '../../util/LoggerUtil.dart';
import '../../util/Objects.dart';
import '../../util/UiUtil.dart';
import 'BaseBloc.dart';

final class CollectSelectCubit extends BaseBloc<CollectSelectEvent, CollectSelectState> {

  final _logger = createLogger();

  CollectSelectCubit(ImSession session) : super(CollectSelectState.init(session)) {
    on<CollectSelectLoadDataEvent>((event, emit) {
      _loadData(state);
    });
    on<CollectSelectAddCollectEvent>((event, emit) {
      _addCollect(state, event.collect);
    });
    on<CollectSelectRemoveCollectEvent>((event, emit) {
      _removeCollect(state, event.collect);
    });
    on<CollectSelectSubmitEvent>((event, emit) {
      _submitData(state, event.context);
    });
  }

  loadData() {
    _loadData(state);
  }

  _loadData(CollectSelectState oldState) async {
    var collectDao = ImCollectDao();
    var messageDao = ImMessageDao();
    var userId = oldState.imSession.currentUserId;
    var search = oldState.search;
    var messageTypes = oldState.messageTypes;
    var collects = await collectDao.getCollects(userId!, search, messageTypes, 500);
    for (var collect in collects) {
      collect.initContent();
      if (collect.messageType == ImMessageType.Chat) {
        if (Objects.isNotNull(collect.message!.refMessageIds)) {
          await messageDao.loadRefMessage(collect.message!);
        } else {
          var message = await messageDao.getByServerIdAndUserId(collect.message!.serverId!, collect.userId);
          await messageDao.loadRefMessage(message!);
          collect.message = message!;
        }
      } else {
        await messageDao.loadRefMessage(collect.message!);
      }
    }
    emit(oldState.copy(collects: collects, loadingState: LoadingState.success));
  }

  _addCollect(CollectSelectState oldState, ImCollect collect) {
    var selectCollects = List.of(oldState.selectCollects);
    if (!selectCollects.contains(collect)) {
      selectCollects.add(collect);
    }
    emit(oldState.copy(selectCollects: selectCollects));
  }

  _removeCollect(CollectSelectState oldState, ImCollect collect) {
    var selectCollects = List.of(oldState.selectCollects);
    if (selectCollects.contains(collect)) {
      selectCollects.remove(collect);
    }
    emit(oldState.copy(selectCollects: selectCollects));
  }

  _submitData(CollectSelectState oldState, BuildContext context) async {
    emit(oldState.copy(isDoing: true));

    try {
      var session = oldState.imSession;
      var messageService = ImMessageSendService();
      var messages = <ImMessage>[];
      for (var collect in oldState.selectCollects) {
        var imMessage = collect.message;
        var messageType = imMessage!.messageType;
        var message = await messageService.buildMessage(session!, imMessage?.content??'', messageType, null);
        messages.add(message);
      }
      UiUtil.uiAddMessages(messages);

      UiUtil.uiChangeSession(session);

      await messageService.sendMessages(session!.currentUserId!, messages);

      if (context.mounted) {
        Navigator.of(context).pop();
      }
    } catch (error) {
      emit(oldState.copy(isDoing: false));
      _logger.i('CollectSelect submit error', time: DateTime.now(), error: error);
    }

  }
}

final class CollectSelectState extends Equatable {

  final ImSession imSession;
  final LoadingState loadingState;
  final List<ImMessageType> messageTypes;
  final String search;
  final List<ImCollect> collects;
  final List<ImCollect> selectCollects;
  final bool isDoing;

  const CollectSelectState._({
    this.loadingState = LoadingState.loading,
    this.messageTypes = const <ImMessageType>[],
    this.search = '',
    this.collects = const <ImCollect>[],
    this.selectCollects = const <ImCollect>[],
    this.isDoing = false,
    required this.imSession,
  });

  const CollectSelectState.init(ImSession imSession) : this._(imSession: imSession);

  CollectSelectState copy({
    List<ImMessageType>? messageTypes,
    String? search,
    List<ImCollect>? collects,
    List<ImCollect>? selectCollects,
    LoadingState? loadingState,
    bool? isDoing,
  }) {
    return CollectSelectState._(
      imSession: imSession,
      messageTypes: messageTypes ?? this.messageTypes,
      search: search ?? this.search,
      collects: collects ?? this.collects,
      selectCollects: selectCollects ?? this.selectCollects,
      loadingState: loadingState ?? this.loadingState,
      isDoing: isDoing ?? this.isDoing,
    );
  }

  @override
  List<Object?> get props => [imSession, loadingState, messageTypes, search, collects, selectCollects, isDoing];

}

abstract class CollectSelectEvent {}
final class CollectSelectLoadDataEvent extends CollectSelectEvent {}
final class CollectSelectAddCollectEvent extends CollectSelectEvent {
  final ImCollect collect;
  CollectSelectAddCollectEvent(this.collect);
}

final class CollectSelectRemoveCollectEvent extends CollectSelectEvent {
  final ImCollect collect;
  CollectSelectRemoveCollectEvent(this.collect);
}

final class CollectSelectSubmitEvent extends CollectSelectEvent {
  final BuildContext context;
  CollectSelectSubmitEvent(this.context);
}